package com.alibaba.smart.framework.engine.simulation;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.alibaba.smart.framework.engine.SmartEngine;
import com.alibaba.smart.framework.engine.bpmn.assembly.event.EndEvent;
import com.alibaba.smart.framework.engine.bpmn.assembly.gateway.AbstractGateway;
import com.alibaba.smart.framework.engine.bpmn.assembly.gateway.ExclusiveGateway;
import com.alibaba.smart.framework.engine.bpmn.assembly.gateway.ParallelGateway;
import com.alibaba.smart.framework.engine.bpmn.assembly.process.SequenceFlow;
import com.alibaba.smart.framework.engine.common.expression.evaluator.MvelExpressionEvaluator;
import com.alibaba.smart.framework.engine.deployment.ProcessDefinitionContainer;
import com.alibaba.smart.framework.engine.exception.EngineException;
import com.alibaba.smart.framework.engine.extension.constant.ExtensionConstant;
import com.alibaba.smart.framework.engine.model.assembly.Activity;
import com.alibaba.smart.framework.engine.model.assembly.ConditionExpression;
import com.alibaba.smart.framework.engine.pvm.PvmActivity;
import com.alibaba.smart.framework.engine.pvm.PvmProcessDefinition;
import com.alibaba.smart.framework.engine.pvm.PvmTransition;

/**
 * @author 高海军 帝奇
 * @date 2019.08.16
 * 根据当前环节id等参数，获取该节点的直接后向环节。 如果直接后向环节是网关型节点，则会继续查找网关型节点的后向节点；否则会返回参数中的该直接后向环节。。
 */
public class ProcessSimulation {

  private SmartEngine smartEngine;

  private MvelExpressionEvaluator mvelExpressionEvaluator = new MvelExpressionEvaluator();

  public ProcessSimulation(SmartEngine smartEngine) {
    this.smartEngine = smartEngine;
  }

  /**
   * 根据当前环节id等参数，获取该节点的直接后向环节。 如果直接后向环节是网关型节点，则会继续查找网关型节点的后向节点；否则会返回参数中的该直接后向环节。
   *
   * @param processDefinitionId
   * @param processDefinitionVersion
   * @param currentActivityId
   * @param simulationContext        执行互斥网关的条件表达式参数
   * @return
   */
  public List<Activity> simulateOutcomingActivities(String processDefinitionId, String processDefinitionVersion,
                                                    String currentActivityId, Map<String, Object> simulationContext) {

    PvmProcessDefinition pvmProcessDefinition = smartEngine.getProcessEngineConfiguration()
        .getAnnotationScanner().getExtensionPoint(ExtensionConstant.SERVICE,
            ProcessDefinitionContainer.class).getPvmProcessDefinition(processDefinitionId,
            processDefinitionVersion);

    PvmActivity currentPvmActivity = pvmProcessDefinition.getActivities().get(currentActivityId);

    if (null == currentPvmActivity) {
      String exceptionMessage = String.format(
          "No PvmActivity found for processDefinitionId :%BehaviorUtil,processDefinitionVersion :%BehaviorUtil,"
              + "currentActivityId :%BehaviorUtil",
          processDefinitionId, processDefinitionVersion, currentActivityId);
      throw new EngineException(exceptionMessage);

    }
    List<Activity> resultList = new ArrayList<Activity>();

    simulation(currentPvmActivity, simulationContext, resultList);

    return resultList;
  }

  void simulation(PvmActivity currentPvmActivity, Map<String, Object> simulationContext, List<Activity> resultList) {

    Map<String, PvmTransition> outComingPvmTransitionMap = currentPvmActivity.getOutcomeTransitions();
    if (null == outComingPvmTransitionMap) {
      // 这种情况下，currentPvmActivity 应该是EndEvent了
      assert currentPvmActivity.getModel().getClass().equals(EndEvent.class);
      //do nothing，
    } else {
      for (Entry<String, PvmTransition> pvmTransitionEntry : outComingPvmTransitionMap.entrySet()) {
        PvmTransition pvmTransition = pvmTransitionEntry.getValue();
        PvmActivity newCurrentPvmActivity = pvmTransition.getTarget();
        Activity newCurrentActivity = newCurrentPvmActivity.getModel();

        //如果新的当前节点是网关型节点
        if (newCurrentActivity instanceof AbstractGateway) {

          if (newCurrentActivity instanceof ExclusiveGateway) {
            Map<String, PvmTransition> outcomeTransitions = newCurrentPvmActivity.getOutcomeTransitions();

            for (Map.Entry<String, PvmTransition> transitionEntry : outcomeTransitions.entrySet()) {
              PvmTransition pendingTransition = transitionEntry.getValue();
              SequenceFlow sequenceFlow = (SequenceFlow) pendingTransition.getModel();
              ConditionExpression conditionExpression = sequenceFlow.getConditionExpression();

              boolean matched = (Boolean) mvelExpressionEvaluator.eval(
                  conditionExpression.getExpressionContent(), simulationContext, true);

              if (matched) {
                Activity chosenActivity = pendingTransition.getTarget().getModel();

                if (chosenActivity instanceof AbstractGateway) {
                  //                        //如果后向直接节点是互斥网关，或者并行网关。
                  //                        那么需要递归处理，因为理论上来讲，互斥网关的节点仍然可能存在互斥网关。那么则要需要再继续分析网关型的后向节点。
                  simulation(newCurrentPvmActivity, simulationContext, resultList);
                } else {
                  resultList.add(chosenActivity);

                }

              }

            }
          } else if (newCurrentActivity instanceof ParallelGateway) {
            Map<String, PvmTransition> outcomeTransitions = newCurrentPvmActivity.getOutcomeTransitions();

            for (Map.Entry<String, PvmTransition> transitionEntry : outcomeTransitions.entrySet()) {
              PvmTransition pendingTransition = transitionEntry.getValue();
              Activity activity = pendingTransition.getTarget().getModel();
              resultList.add(activity);

            }
          } else {
            throw new EngineException("Not support:" + newCurrentActivity);
          }

        } else {
          resultList.add(newCurrentActivity);
        }
      }
    }

  }

}
